package cn.newzai.parser.proto

import scala.util.parsing.combinator.syntactical.StandardTokenParsers
import scala.io.{Codec, Source}
import  result._



/**
 * Created with IntelliJ IDEA.
 * User: chenxiaohong
 * Date: 13-6-4
 * Time: 上午8:42
 * To change this template use File | Settings | File Templates.
 */
class GoogleProtobufParser(val dir : String,
                            val file :String,
                            val encoding : String) extends StandardTokenParsers{
  lexical.delimiters += (";","=","{","}","[","]",".")

  lexical.reserved += ("import","package","enum","message","required","optional","repeated","default")

  def parserImport :Parser[String]= {
    "import"~stringLit~";" ^^ {
      case "import"~importFile~";" =>
        val importParser = GoogleProtobufParser(dir,importFile,encoding)
        importParser.parserFile
      ""
    }
  }
  def parserPackage = {
    "package"~repsep(ident,".")~";" ^^ {
      case "package"~paths~";" =>

        Message.package_name = paths.mkString(".")
      ""
    }
  }

  def parserEnumValue = {
    ident~"="~numericLit~";" ^^ {
      case name ~ "="~value ~";" =>
        (name,value.toInt)
    }
  }
  def parserEnum = {
    "enum"~ident~"{"~rep(parserEnumValue)~"}"~opt(";") ^^ {
      case "enum"~ name ~"{"~values~"}" ~x=>

        Enum(name,values.toArray)
      ""
    }
  }

  def parserFieldDefauleValue ={
    "[" ~ "default" ~ "=" ~ (ident|stringLit|numericLit)~"]"  ^^ {
      case "["~"default"~"="~value~"]" =>
        value
    }
  }
  def parserField = {
    ("required"|"optional"|"repeated")~ident~ident~"="~numericLit~opt(parserFieldDefauleValue)~";" ^^ {
      case limit_ ~ type_ ~ name_ ~ "=" ~ index ~ None ~ ";"=>
        Field(limit_,type_,name_,index.toInt,null)
      case limit_ ~ type_ ~ name_ ~ "=" ~ index ~ Some(default) ~ ";"=>
        Field(limit_,type_,name_,index.toInt,default)
    }

  }

  def parserMessage = {
    "message"~ident~"{"~rep(parserField)~"}"~opt(";") ^^ {
      case "message"~name~"{"~fields~"}"~x =>
        Message(name,fields.toArray)
    }
  }

  def parserProto = {
    rep(parserImport)~parserPackage~rep(parserEnum|parserMessage) ^^ {
      case imports ~ pack ~ contents =>
       ""
    }
  }

  def parserAll[T]( p : Parser[T], in :String) ={
    phrase(p)( new lexical.Scanner(in))
  }

  def parserFile ={
    val fileName = s"${dir}\\${file}"
    implicit  val codec = Codec(encoding)
    parserAll(parserProto, Source.fromFile(fileName).getLines().mkString("\n"))
  }
}

object  GoogleProtobufParser{

  def apply(dir :String, file :String, encoding :String) ={
    new GoogleProtobufParser(dir,file,encoding)
  }

}